package by.pavlyukevich.paymentsystem.dataaccess.card.impl;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.stereotype.Repository;

import by.pavlyukevich.paymentsystem.dataaccess.card.CardLimitDao;
import by.pavlyukevich.paymentsystem.dataaccess.filter.CardLimitFilter;
import by.pavlyukevich.paymentsystem.dataaccess.filter.Filter;
import by.pavlyukevich.paymentsystem.dataaccess.impl.AbstractDaoImpl;
import by.pavlyukevich.paymentsystem.datamodel.card.CardLimit;
import by.pavlyukevich.paymentsystem.datamodel.card.CardLimit_;

@Repository
public class CardLimitDaoImpl extends AbstractDaoImpl<Integer, CardLimit> implements CardLimitDao {

	protected CardLimitDaoImpl() {
		super(CardLimit.class);
	}

	@Override
	public List<CardLimit> getList(Filter<CardLimit> cardLimitFilter) {

		CriteriaQuery<CardLimit> criteria = getAllCriteria(cardLimitFilter);
		addCriteriaRestrict(criteria, cardLimitFilter);

		Root<CardLimit> root = getRoot(criteria, CardLimit.class);
		root.fetch(CardLimit_.card);
		return getList(criteria, cardLimitFilter);
	}

	@Override
	public long getCount(Filter<CardLimit> cardLimitFilter) {
		CriteriaQuery<Long> criteria = getCountAllCriteria();
		addCriteriaRestrict(criteria, cardLimitFilter);
		return getSingle(criteria);
	}

	private <T> CriteriaQuery<T> addCriteriaRestrict(CriteriaQuery<T> criteria,
			Filter<CardLimit> filter) {
		if (filter == null) {
			return criteria;
		}
		Root<CardLimit> root = getRoot(criteria, CardLimit.class);
		CriteriaBuilder cBuilder = getEntityManager().getCriteriaBuilder();
		List<Predicate> predicateList = new ArrayList<Predicate>();
		CardLimitFilter cardLimitFilter = (CardLimitFilter) filter;
		if (cardLimitFilter.getCard() != null) {
			predicateList.add(cBuilder.equal(root.get(CardLimit_.card), cardLimitFilter.getCard()));
		}
		if (cardLimitFilter.getDate() != null) {
			predicateList.add(cBuilder.lessThanOrEqualTo(root.get(CardLimit_.periodBegin),
					cardLimitFilter.getDate()));
			predicateList.add(cBuilder.greaterThanOrEqualTo(root.get(CardLimit_.periodEnd),
					cardLimitFilter.getDate()));
		}
		if (predicateList.size() > 0) {
			Predicate predicateArray[] = predicateList.toArray(new Predicate[0]);
			criteria.where(predicateArray);
		}
		return criteria;
	}
}
